package com.xbongbong.saas.model.impl;

import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasStageEntity;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.pro.enums.errorcodes.OpportunityErrorCodeEnum;
import com.xbongbong.pro.opportunity.pojo.vo.SaleStageModifyLogVO;
import com.xbongbong.saas.domain.dao.SaleStageModifyLogDao;
import com.xbongbong.saas.domain.entity.SaleStageEntity;
import com.xbongbong.saas.domain.entity.SaleStageModifyLogEntity;
import com.xbongbong.saas.domain.entity.StageWorkEntity;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.dictionary.SaleStageModifyLogTypeEnum;
import com.xbongbong.saas.model.OpportunityStageLogModel;
import com.xbongbong.saas.model.SaleStageModel;
import com.xbongbong.saas.model.SaleStageModifyLogModel;
import com.xbongbong.saas.model.SaleStageSyncStatusModel;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author haibin.zhang
 * @version v1.0
 * @date 2019/2/14 12:19
 * @since v1.0
 */
@Service
public class SaleStageModifyLogModelImpl implements SaleStageModifyLogModel {

    @Resource
    private SaleStageModifyLogDao saleStageModifyLogDao;
    @Resource
    private SaleStageModel saleStageModel;
    @Resource
    private OpportunityStageLogModel opportunityStageLogModel;
    @Resource
    private SaleStageSyncStatusModel saleStageSyncStatusModel;

    @Override
    public Integer insert(SaleStageModifyLogEntity entity) throws XbbException {
        entity.setAddTime((long) DateUtil.getInt());
        entity.setUpdateTime((long) DateUtil.getInt());
        return saleStageModifyLogDao.insert(entity);
    }

    @Override
    public Integer update(SaleStageModifyLogEntity entity) throws XbbException {
        entity.setUpdateTime((long) DateUtil.getInt());
        return saleStageModifyLogDao.update(entity);
    }

    @Override
    public List<SaleStageModifyLogEntity> findEntitys(Map<String, Object> param) {
        return saleStageModifyLogDao.findEntitys(param);
    }

    @Override
    public Integer getEntitysCount(Map<String, Object> param) {
        return saleStageModifyLogDao.getEntitysCount(param);
    }

    @Override
    public List findEntitysWithoutSub(Map<String, Object> param) {
        return null;
    }

    @Override
    public SaleStageModifyLogEntity getByKey(Long key, String corpid) {
        return saleStageModifyLogDao.getByKey(key, corpid);
    }

    @Override
    public Integer save(SaleStageModifyLogEntity saleStageModifyLog) throws XbbException {
        if (saleStageModifyLog.getId() != null) {
            return update(saleStageModifyLog);
        } else {
            return insert(saleStageModifyLog);
        }
    }

    @Override
    public void insertBatch(List<SaleStageModifyLogEntity> list) {
        saleStageModifyLogDao.insertBatch(list);
    }

    @Override
    public Integer deleteBatch(List<SaleStageModifyLogEntity> saleStageModifyLogList, String corpid) {
        return saleStageModifyLogDao.deleteBatch(saleStageModifyLogList, corpid);
    }

    @Override
    public SaleStageModifyLogVO getNeedSyncStageIdList(String corpid, Long formId, Long stageProcessId) {
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid", corpid);
        param.put("formId", formId);
        param.put("stageProcessId", stageProcessId);
        param.put("del", 0);
        List<SaleStageModifyLogEntity> saleStageModifyLogList = findEntitys(param);

        List<SaleStageEntity> saleStageList = saleStageModel.findEntitys(param);
        saleStageList = saleStageList.stream().sorted(Comparator.comparing(SaleStageEntity::getSort).reversed()).collect(Collectors.toList());
        Map<Long, SaleStageEntity> saleStageMap = saleStageList.stream().collect(Collectors.toMap(SaleStageEntity::getId, Function.identity()));

        Set<Long> saleStageIdList = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (SaleStageModifyLogEntity modifyLog : saleStageModifyLogList) {
            saleStageIdList.add(modifyLog.getStageId());
            if (Objects.equals(modifyLog.getType(), SaleStageModifyLogTypeEnum.STAGE_OUT_PROPORTION_CHANGE.getCode())) {
                // 如果是编辑阶段比例，那么还需要获取编辑的阶段的下一阶段
                SaleStageEntity currentStage = saleStageMap.get(modifyLog.getStageId());
                if (Objects.isNull(currentStage)) {
                    continue;
                }
                SaleStageEntity nextStage = saleStageList.stream().filter(stage -> stage.getSort() < currentStage.getSort()).findFirst().orElse(null);
                if (Objects.isNull(nextStage)) {
                    continue;
                }
                saleStageIdList.add(nextStage.getId());
            }
        }

        return new SaleStageModifyLogVO(saleStageModifyLogList, saleStageIdList);
    }

    /**
     * 编辑销售阶段时保存阶段比例的变更记录
     *
     * @param corpid          公司id
     * @param formId          表单id
     * @param stageProcessId  阶段流程id
     * @param businessType    业务类型
     * @param updateStageList 编辑后的阶段数据
     */
    @Override
    public void saveModifyLogWhenUpdateStage(String corpid, Long formId, Long stageProcessId, Integer businessType, List<PaasStageEntity> updateStageList) throws XbbException{
        // 如果销售机会阶段的阶段比例发生了变更，需要将对应的变更记录保存到tb_sale_stage_modify_log
        if (CollectionsUtil.isEmpty(updateStageList) || !Objects.equals(businessType, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode())) {
            return;
        }
        // 当有任务还在同步的时候，不能对流程进行编辑
        if (saleStageSyncStatusModel.isSyncStatusInProgress(corpid, formId, stageProcessId)) {
            throw new XbbException(OpportunityErrorCodeEnum.API_ERROR_202026);
        }
        // 如果阶段流程下还没有关联的销售机会数据，那么不需要保存变更记录
        // 因为保存变更记录的目的是为了之后同步机会主数据，所以还没有数据关联时进行的变更是没有意义的，不会对同步数据产生影响
        if (!opportunityStageLogModel.existOpportunityByStageProcessId(corpid, formId, stageProcessId)) {
            return;
        }
        List<Long> stageIdIn = updateStageList.stream().map(PaasStageEntity::getId).collect(Collectors.toList());
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid", corpid);
        param.put("formId", formId);
        param.put("stageProcessId", stageProcessId);
        param.put("idIn", stageIdIn);
        param.put("del", 0);
        List<SaleStageEntity> saleStageList = saleStageModel.findEntitys(param);
        Map<Long, SaleStageEntity> saleStageMap = saleStageList.stream().collect(Collectors.toMap(SaleStageEntity::getId, Function.identity()));
        List<SaleStageModifyLogEntity> insertSaleStageModifyLogList = new ArrayList<>();
        for (PaasStageEntity currentStage : updateStageList) {
            Long stageId = currentStage.getId();
            SaleStageEntity originalStage = saleStageMap.get(stageId);
            if (Objects.isNull(originalStage)) {
                continue;
            }
            if (!Objects.equals(currentStage.getOutProportion(), originalStage.getOutProportion())) {
                // 当前的跳出比例和原始的跳出比例不一致，代表编辑了阶段比例
                SaleStageModifyLogEntity saleStageModifyLog = new SaleStageModifyLogEntity(corpid, formId, stageProcessId, stageId, null,
                        SaleStageModifyLogTypeEnum.STAGE_OUT_PROPORTION_CHANGE.getCode(), originalStage.getOutProportion(), currentStage.getOutProportion());
                insertSaleStageModifyLogList.add(saleStageModifyLog);
            } else if (!Objects.equals(currentStage.getIntoProportion(), originalStage.getIntoProportion())) {
                SaleStageModifyLogEntity saleStageModifyLog = new SaleStageModifyLogEntity(corpid, formId, stageProcessId, stageId, null,
                        SaleStageModifyLogTypeEnum.STAGE_INTO_PROPORTION_CHANGE.getCode(), originalStage.getIntoProportion(), currentStage.getIntoProportion());
                insertSaleStageModifyLogList.add(saleStageModifyLog);
            }
        }
        if (CollectionsUtil.isNotEmpty(insertSaleStageModifyLogList)) {
            insertBatch(insertSaleStageModifyLogList);
        }
    }

    @Override
    public void saveModifyLogWhenUpdateStageWork(Integer businessType, StageWorkEntity currentStageWork, StageWorkEntity originalStageWork) throws XbbException {
        if (Objects.isNull(originalStageWork) || Objects.isNull(currentStageWork) ||
                !Objects.equals(businessType, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode()) ||
                Objects.equals(currentStageWork.getProportion(), originalStageWork.getProportion())) {
            return;
        }
        String corpid = currentStageWork.getCorpid();
        Long formId = currentStageWork.getFormId();
        Long stageProcessId = currentStageWork.getStageProcessId();
        Long stageId = currentStageWork.getStageId();
        Long stageWorkId = currentStageWork.getId();
        // 当有任务还在同步的时候，不能对流程进行编辑
        if (saleStageSyncStatusModel.isSyncStatusInProgress(corpid, formId, stageProcessId)) {
            throw new XbbException(OpportunityErrorCodeEnum.API_ERROR_202026);
        }
        // 如果阶段流程下还没有关联的销售机会数据，那么不需要保存变更记录
        // 因为保存变更记录的目的是为了之后同步机会主数据，所以还没有数据关联时进行的变更是没有意义的，不会对同步数据产生影响
        if (!opportunityStageLogModel.existOpportunityByStageProcessId(corpid, formId, stageProcessId)) {
            return;
        }
        SaleStageModifyLogEntity saleStageModifyLog = new SaleStageModifyLogEntity(corpid, formId, stageProcessId, stageId, stageWorkId,
                SaleStageModifyLogTypeEnum.STAGE_WORK_PROPORTION_CHANGE.getCode(), originalStageWork.getProportion(), currentStageWork.getProportion());
        insert(saleStageModifyLog);
    }

    @Override
    public void saveModifyLogWhenDeleteStageWork(Integer businessType, StageWorkEntity currentStageWork) throws XbbException {
        if (Objects.isNull(currentStageWork) || !Objects.equals(businessType, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode())) {
            return;
        }
        String corpid = currentStageWork.getCorpid();
        Long formId = currentStageWork.getFormId();
        Long stageProcessId = currentStageWork.getStageProcessId();
        Long stageId = currentStageWork.getStageId();
        Long stageWorkId = currentStageWork.getId();
        // 当有任务还在同步的时候，不能对流程进行编辑
        if (saleStageSyncStatusModel.isSyncStatusInProgress(corpid, formId, stageProcessId)) {
            throw new XbbException(OpportunityErrorCodeEnum.API_ERROR_202026);
        }
        // 如果阶段流程下还没有关联的销售机会数据，那么不需要保存变更记录
        // 因为保存变更记录的目的是为了之后同步机会主数据，所以还没有数据关联时进行的变更是没有意义的，不会对同步数据产生影响
        if (!opportunityStageLogModel.existOpportunityByStageProcessId(corpid, formId, stageProcessId)) {
            return;
        }
        SaleStageModifyLogEntity saleStageModifyLog = new SaleStageModifyLogEntity(corpid, formId, stageProcessId, stageId, stageWorkId,
                SaleStageModifyLogTypeEnum.STAGE_WORK_DELETE.getCode(), currentStageWork.getProportion(), currentStageWork.getProportion());
        insert(saleStageModifyLog);
    }
}
